#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <termios.h>
#include <unistd.h>

void calendar(int nyear, int nmonth);
void display(int nyear, int nmonth, int tdays, int days[]);
void gotoxy(int x, int y);
void clrscr();
int getkey();
void year_err();

char *months[] = {"January", "Februrary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
char *weeks[] = {"Mon", "Tue", "Web", "Thu", "Fri", "Sat", "Sun"};

 
/* reads from keypress, doesn't echo */
int getch2(void) {
    struct termios oldattr, newattr;
    int ch;
    tcgetattr( STDIN_FILENO, &oldattr );
    newattr = oldattr;
    newattr.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
    return ch;
}
 
int main() {
	int nmonth, nyear;

	while (1) {
		printf("\t\t\t\tEnter year and month(number): ");
		scanf("%d %d", &nyear, &nmonth);
		if (nyear < 1945) {
			printf("\t\t\t\t\033[0;31mPlease enter year above 1945\033[0m\n");
			continue;
		} else {
			calendar(nyear, nmonth);
		}

		getchar(); // get rid of '\n'
		while (1) {
			gotoxy(20, 20);
			printf("(*) Use j(left), l(right), i(up) and k(down) arrow.");
			gotoxy(20, 22);
			// printf("(*) Press P to go to particular year and month");
			// gotoxy(20, 24);
			printf("(*) Press ESC to Exit.");

			// initscr();
			int ch = getch2();
			// endwin();

			switch (ch) {
				case 'k': // down 向下箭头
					// 如果是十二月份，跳到下一年
					if (nmonth == 12) {
						nmonth = 1;
						nyear++;
					} else {
						nmonth++;
					}
					calendar(nyear, nmonth);
					break;
				case 'i': // up
					if (nyear == 1945 && nmonth == 1) {
						year_err();
						break;
					}

					// 跳到前年
					if (nmonth == 1) {
						nyear--;
						nmonth = 12;
					} else {
						nmonth--;
					}
					calendar(nyear, nmonth);
					break;

				case 'l': // right
					nyear++;
					calendar(nyear, nmonth);
					break;
				case 'j':
					if (nyear == 1945) {
						year_err();
					} else {
						nyear--;
						calendar(nyear, nmonth);
					}
					break;
				case 27: // ESC
					clrscr();
					gotoxy(50, 14);
					printf("Exiting program.\n\n\n\n");
					exit(0);
			}
		}
	}
	return 0;
}

void year_err() {
	gotoxy(30, 2);
	printf("\033[0;31mYear below 1945 not available!\033[0m\n");
}

// curses库getch的使用
// https://blog.csdn.net/xiaoweige207/article/details/6206265
int getkey() {
	initscr();
	int ch;

	ch = getch();
	if (ch == 0) {
		printf("zero");
		fflush(stdout);
		ch = getch();
		return ch;
	}

	endwin();
	return ch;
}

// x表示离左边多远，y表示离上边多远
void gotoxy(int x, int y) {
	// TODO:???
	printf("%c[%d;%df", 0x1B, y, x);
}

void clrscr() {
	system("clear");
}

void calendar(int nyear, int nmonth) {
	int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int tdays = 0;
	int k;
	clrscr();

	if (nyear > 1945) {
		for (k = 1945; k < nyear; k++) {
			// 闰年
			if (nyear % 4 == 0 && nyear % 100 != 0 || nyear % 400 == 0) {
				tdays += 366;
			} else {
				tdays += 365;
			}
		}
	}

	if (nyear % 4 == 0 && nyear % 100 != 0 || nyear % 400 == 0) 
			days[1] += 1; // 二月有29天

	for (k = 0; k < nmonth-1; k++) {
		tdays += days[k]; // 加上前一个月的天数
	}
	tdays %= 7; 
	display(nyear, nmonth, tdays, days);
}

void display(int nyear, int nmonth, int tdays, int days[]) {
	int pos, i, j;
	clrscr();
	gotoxy(36, 6);
	printf("\033[0;31m%s %d\033[0m\n", months[nmonth-1], nyear);	

	for (i = 0, pos = 30; i < 7; i++, pos += 10) {
		gotoxy(pos, 8);
		if (i == 6)
			// 周日为蓝色,其他为绿色
			printf("\033[0;34m%s\033[0m", weeks[i]);
		else 
			printf("\033[0;32m%s\033[0m", weeks[i]);
	}

	// TODO: ???
	tdays--;
	switch (tdays) {
		case 0:
		case 7:
			pos = 91;
			break;
		case 1:
			pos = 31;
			break;
		case 2:
			pos = 41;
			break;
		case 3:
			pos = 51;
			break;
		case 4:
			pos = 61;
			break;
		case 5:
			pos = 71;
			break;
		case 6:
			pos = 81;
			break;
	}

	for (i = 0, j = 10; i < days[nmonth-1]; i++, pos += 10) {
		gotoxy(pos, j);
		if (pos == 91) 
			printf("\033[0;36m%d\033[0m", i + 1);
		else 
			printf("\033[0;32m%d\033[0m", i + 1);

		if (pos == 91) {
			pos = 21;
			j++; 
		}
	}

	printf("\033[0;35m");
	for (i = 22; i < 102; i++) {
		gotoxy(i, 4);
		printf("%c", '-');
		gotoxy(i, 17);
		printf("%c", '-');
	}

	/*
	for (i = 5; i < 17; i++) {
		gotoxy(21, i);
		printf("%c", '*');
		gotoxy(102, i);
		printf("%c", '*');
	}
	*/

	printf("\033[0m\n\n");
}
